package me.kuye.jkuye.aop;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import me.kuye.jkuye.core.Action;
import me.kuye.jkuye.core.Controller;
import net.sf.cglib.proxy.MethodProxy;

public class Invocation {
	private Action action;
	private static final Object[] NULL_ARGS = new Object[0];

	boolean useInjectTarget;

	private Object target;
	private Interceptor[] interceptors;
	private Object[] args;
	private Method method;
	private MethodProxy methodProxy;
	private Object returnValue;
	private int index = 0;

	protected Invocation() {
	}

	public Invocation(Controller controller, Action action) {
		this.target = controller;
		this.interceptors = action.getInterceptors();
		this.action = action;
		this.args = NULL_ARGS;
	}

	public Invocation(Object target, Method method, Object[] args, MethodProxy methodProxy, Interceptor[] inters) {
		this.target = target;
		this.method = method;
		this.args = args;
		this.methodProxy = methodProxy;
		this.interceptors = inters;
	}

	public void invoke() {
		if (index < interceptors.length) {
			interceptors[index].intercept(this);
		} else if (index++ == interceptors.length) {
			try {
				if (action != null) {
					returnValue = action.getMethod().invoke(target, args);
				} else {
					if (useInjectTarget) {
						returnValue = methodProxy.invoke(target, args);
					} else {
						returnValue = methodProxy.invokeSuper(target, args);
					}
				}
			} catch (InvocationTargetException e) {
				Throwable t = e.getTargetException();
				throw t instanceof RuntimeException ? (RuntimeException) t : new RuntimeException(e);
			} catch (RuntimeException e) {
				throw e;
			} catch (Throwable t) {
				throw new RuntimeException(t);
			}

		}
	}
}
